package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"log"
	"strconv"

	"gitee.com/lilihli/connector/api"
	"github.com/gin-gonic/gin"
)

func main() {
	cfg, err := ReadConfig()
	if err != nil {
		log.Printf("ReadConfig failed, %v", err)
		return
	}

	r := gin.Default()

	//买入指定金额的股票
	r.GET("/buyMoney/:clientType/:name/:symbol/:money/:sign", func(c *gin.Context) {
		clientType := c.Param("clientType")
		name := c.Param("name")
		symbol := c.Param("symbol")
		moneyStr := c.Param("money")
		sign := c.Param("sign")

		sign2, err := hmacSha256(cfg.HmacPwd, clientType, name, symbol, moneyStr)
		if err != nil {
			errorMsg(c, fmt.Errorf("hmacSha256 failed, %v", err))
			return
		}
		if sign != sign2 {
			errorMsg(c, fmt.Errorf("signature error, %v", err))
			return
		}

		money, err := strconv.ParseFloat(moneyStr, 64)
		if err != nil {
			errorMsg(c, fmt.Errorf("strconv.ParseFloat money failed, %v", err))
			return
		}
		// log.Println("buy:", clientType, name, symbol, money)
		// c.JSON(200, gin.H{
		// 	"status":   "success",
		// 	"buyCount": 1000,
		// 	"buyMoney": 10000,
		// })

		opt := api.GetOperator(clientType)
		err = opt.ConnectClient()
		if err != nil {
			errorMsg(c, fmt.Errorf("opt.ConnectClient failed, %v", err))
			return
		}
		buyCount, buyMoney, err := opt.BuyMoney(name, symbol, money)
		if err != nil {
			errorMsg(c, fmt.Errorf("opt.Sale failed, %v", err))
			return
		}

		c.JSON(200, gin.H{
			"status":   "success",
			"buyCount": buyCount,
			"buyMoney": buyMoney,
		})
	})

	//买入指定数量的股票
	r.GET("/buyNumber/:clientType/:name/:symbol/:number/:sign", func(c *gin.Context) {
		clientType := c.Param("clientType")
		name := c.Param("name")
		symbol := c.Param("symbol")
		numberStr := c.Param("number")
		sign := c.Param("sign")

		sign2, err := hmacSha256(cfg.HmacPwd, clientType, name, symbol, numberStr)
		if err != nil {
			errorMsg(c, fmt.Errorf("hmacSha256 failed, %v", err))
			return
		}
		if sign != sign2 {
			errorMsg(c, fmt.Errorf("signature error, %v", err))
			return
		}

		number, err := strconv.ParseUint(numberStr, 10, 64)
		if err != nil {
			errorMsg(c, fmt.Errorf("strconv.ParseUint %s failed, %v", numberStr, err))
			return
		}
		// log.Println("buy:", clientType, name, symbol, money)
		// c.JSON(200, gin.H{
		// 	"status":   "success",
		// 	"buyCount": 1000,
		// 	"buyMoney": 10000,
		// })

		opt := api.GetOperator(clientType)
		err = opt.ConnectClient()
		if err != nil {
			errorMsg(c, fmt.Errorf("opt.ConnectClient failed, %v", err))
			return
		}

		money, err := opt.BuyNumber(name, symbol, number)
		if err != nil {
			errorMsg(c, fmt.Errorf("opt.Sale failed, %v", err))
			return
		}

		c.JSON(200, gin.H{
			"status": "success",
			"money":  money,
		})
	})

	r.GET("/sale/:clientType/:name/:symbol/:count/:sign", func(c *gin.Context) {
		clientType := c.Param("clientType")
		name := c.Param("name")
		symbol := c.Param("symbol")
		countStr := c.Param("count")
		sign := c.Param("sign")

		sign2, err := hmacSha256(cfg.HmacPwd, clientType, name, symbol, countStr)
		if err != nil {
			errorMsg(c, fmt.Errorf("hmacSha256 failed, %v", err))
			return
		}
		if sign != sign2 {
			errorMsg(c, fmt.Errorf("signature error, %v", err))
			return
		}

		count, err := strconv.ParseUint(countStr, 10, 64)
		if err != nil {
			errorMsg(c, fmt.Errorf("strconv.ParseFloat count failed, %v", err))
			return
		}
		// log.Println("sale:", clientType, name, symbol, count)
		// c.JSON(200, gin.H{
		// 	"status": "success",
		// 	"money":  10000,
		// })

		opt := api.GetOperator(clientType)
		err = opt.ConnectClient()
		if err != nil {
			errorMsg(c, fmt.Errorf("opt.ConnectClient failed, %v", err))
			return
		}
		money, err := opt.Sale(name, symbol, count)
		if err != nil {
			errorMsg(c, fmt.Errorf("opt.Sale failed, %v", err))
			return
		}

		c.JSON(200, gin.H{
			"status": "success",
			"money":  money,
		})
	})

	addr := fmt.Sprintf("%s:%d", cfg.Listening.Address, cfg.Listening.Port)
	err = r.Run(addr)
	if err != nil {
		log.Printf("r.Run failed, %v", err)
		return
	}
}

func errorMsg(c *gin.Context, err error) {
	c.Error(err)
	c.JSON(200, gin.H{
		"status": "error",
		"error":  err.Error(),
	})
}

func hmacSha256(pwd string, msg ...string) (string, error) {
	h := hmac.New(sha256.New, []byte(pwd))
	for _, m := range msg {
		_, err := h.Write([]byte(m))
		if err != nil {
			return "", fmt.Errorf("h.Write failed, %v", err)
		}
	}

	return hex.EncodeToString(h.Sum(nil)), nil
}
